home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
Dev
/
Oberon
/
source
/
OC
/
OCI.mod
< prev
next >
Wrap
Text File
|
1995-06-29
|
14KB
|
447 lines
(*************************************************************************
$RCSfile: OCI.mod $
Description: Common routines used by modules OCE, OCP, OCH and Compiler
Created by: fjc (Frank Copeland)
$Revision: 5.17 $
$Author: fjc $
$Date: 1995/06/02 18:38:40 $
Copyright © 1993-1995, Frank Copeland
This module forms part of the OC program
See OC.doc for conditions of use and distribution
Log entries are at the end of the file.
*************************************************************************)
<* STANDARD- *> <* MAIN- *> <*$ LongVars+ *>
MODULE OCI;
IMPORT OCM, OCS, OCT, OCC;
(* --- Local declarations --------------------------------------------- *)
CONST
(* object modes *)
Var = OCM.Var; VarR = OCM.VarR; VarX = OCM.VarX; Ind = OCM.Ind;
IndR = OCM.IndR; IndX = OCM.IndX; RegI = OCM.RegI; RegX = OCM.RegX;
Lab = OCM.Lab; LabI = OCM.LabI; Con = OCM.Con; Push = OCM.Push;
Pop = OCM.Pop; Coc = OCM.Coc; Reg = OCM.Reg; Fld = OCM.Fld;
Typ = OCM.Typ; Abs = OCM.Abs; XProc = OCM.XProc; LProc = OCM.LProc;
Undef = OCM.Undef; CallBack = OCM.CallBack;
addressableSet =
{ Var, VarX, Ind, IndR, IndX, Reg, RegI, RegX, Con, XProc, LProc,
CallBack };
(* structure forms *)
Char = OCT.Char; DynArr = OCT.DynArr; String = OCT.String;
TagTyp = OCT.TagTyp;
(* CPU Registers *)
D0 = 0; D1 = 1; D7 = 7; A0 = 8; A3 = 11; A4 = 12; A5 = 13; A6 = 14;
A7 = 15; BP = A4 - 8; FP = A5 - 8; SP = A7 - 8;
DataRegs = {D0 .. D7};
AdrRegs = {A0 .. A7};
(* Data sizes *)
B = 1; W = 2; L = 4;
(* --- Procedure declarations ------------------------------------------- *)
(*------------------------------------*)
(*
Explicitly frees any registers used by x
*)
PROCEDURE Unload * (VAR x : OCT.Item);
BEGIN (* Unload *)
IF x.mode IN {VarX, IndX, Reg, RegI, RegX, Push, Pop} THEN
OCC.FreeReg (x);
END
END Unload;
(*------------------------------------*)
PROCEDURE Load * (VAR x : OCT.Item);
VAR y : OCT.Item;
BEGIN (* Load *)
IF x.mode < Reg THEN
IF OCC.InDataReg (x.obj) THEN OCC.GetDReg (x, x.obj)
ELSE
y := x; OCC.GetDReg (x, x.obj); OCC.Move (y.typ.size, y, x);
Unload (y)
END;
ELSIF x.mode > Reg THEN OCS.Mark (126)
END
END Load;
(*------------------------------------*)
PROCEDURE EXT * (size, reg : LONGINT);
BEGIN (* EXT *)
(* OCM.TraceIn (mname, pname); *)
IF size = L THEN OCC.PutWord (OCC.EXTL + reg)
ELSE OCC.PutWord (OCC.EXTW + reg)
END
END EXT;
(*------------------------------------*)
PROCEDURE DescItem * (VAR item : OCT.Item; desc : OCT.Desc; adr : LONGINT);
BEGIN (* DescItem *)
IF desc = NIL THEN
OCS.Mark (963);
item.lev := 0; item.mode := Var;
item.a0 := 0; item.a1 := 0; item.a2 := 0
ELSE
(* item = bound descr *)
item.lev := desc.lev; item.mode := desc.mode; item.a0 := desc.a0;
item.a1 := desc.a1; item.a2 := desc.a2;
IF item.mode IN {Var, VarR, VarX} THEN INC (item.a0, adr)
ELSIF item.mode IN {Ind, IndR, IndX, RegI, RegX} THEN INC (item.a1, adr)
ELSE OCS.Mark (322)
END
END;
item.desc := desc; item.typ := OCT.linttyp; item.wordIndex := FALSE
END DescItem;
(*------------------------------------*)
PROCEDURE UpdateDesc * (VAR x : OCT.Item; adr : LONGINT);
VAR desc : OCT.Desc;
BEGIN (* UpdateDesc *)
desc := x.desc;
IF desc # NIL THEN
desc.lev := x.lev; desc.mode := x.mode; desc.a0 := x.a0;
desc.a1 := x.a1; desc.a2 := x.a2;
IF desc.mode IN {Var, VarX} THEN DEC (desc.a0, adr)
ELSIF desc.mode IN {Ind, IndR, IndX, RegI, RegX} THEN DEC (desc.a1, adr)
ELSE OCS.Mark (322)
END
END
END UpdateDesc;
(*------------------------------------*)
PROCEDURE UnloadDesc * (VAR x : OCT.Item);
VAR desc : OCT.Desc; reg : OCT.Item;
BEGIN (* UnloadDesc *)
desc := x.desc;
IF desc # NIL THEN
IF desc.mode IN {VarX, IndX, RegI, RegX} THEN
IF desc.mode # x.mode THEN
DescItem (reg, desc, 0); OCC.FreeReg (reg)
ELSE
reg.mode := Reg;
IF desc.mode IN {RegI, RegX} THEN
IF desc.a0 # x.a0 THEN reg.a0 := desc.a0; OCC.FreeReg (reg) END
END;
IF desc.mode IN {VarX, IndX, RegX} THEN
IF desc.a2 # x.a2 THEN reg.a0 := desc.a2; OCC.FreeReg (reg) END
END;
END
END;
desc.mode := Undef
END;
END UnloadDesc;
(*------------------------------------*)
PROCEDURE Adr * (VAR x : OCT.Item);
VAR
reg, len, y : OCT.Item; module : OCT.Module; off : LONGINT;
dreg : INTEGER; wordIndex : BOOLEAN; desc : OCT.Desc;
(*------------------------------------*)
PROCEDURE Multiply (VAR lhs, rhs : OCT.Item);
VAR R : OCC.RegState;
BEGIN (* Multiply *)
OCC.LoadRegParams2 (R, lhs, rhs);
OCC.CallKernel (OCC.kMul32);
OCC.RestoreRegisters (R, lhs);
Unload (rhs)
END Multiply;
BEGIN (* Adr *)
IF x.mode IN addressableSet THEN
IF x.mode = Con THEN
IF (x.typ # OCT.stringtyp) & (x.typ # OCT.tagtyp) THEN
OCS.Mark (127)
ELSE
IF (x.typ = OCT.stringtyp) & (x.a1 < 3) THEN
OCC.AllocStringFromChar (x)
END;
IF OCM.SmallData THEN
y := x; OCC.GetAReg (x, NIL);
OCC.PutF2 (OCC.LEA, y, x.a0); Unload (y)
ELSE
x.mode := LabI; x.a1 := L
END
END
ELSIF x.typ.form = DynArr THEN
len.mode := Undef;
IF x.mode IN {IndX, RegX} THEN
reg.mode := Reg; reg.a0 := x.a2; reg.typ := OCT.linttyp;
END;
WHILE x.typ.form = DynArr DO
IF x.mode IN {IndX, RegX} THEN
DescItem (len, x.desc, x.typ.adr); Multiply (reg, len)
END;
x.typ := x.typ.BaseTyp
END;
Unload (len);
IF x.mode = Var THEN x.mode := Ind; x.a1 := 0 END;
Adr (x)
ELSIF x.mode = Reg THEN
IF x.a0 IN DataRegs THEN OCS.Mark (127) END
ELSIF x.mode = Var THEN
y := x; OCC.GetAReg (x, NIL);
OCC.PutF2 (OCC.LEA, y, x.a0); Unload (y)
ELSIF x.mode = Ind THEN
IF x.a1 = 0 THEN
x.mode := Var
ELSE
y := x; OCC.GetAReg (x, NIL);
OCC.PutF2 (OCC.LEA, y, x.a0); Unload (y)
END
ELSIF x.mode IN {VarX, IndX, RegX} THEN
y := x; desc := x.desc;
OCC.GetAReg (x, NIL); x.desc := desc;
OCC.PutF2 (OCC.LEA, y, x.a0); Unload (y)
ELSIF x.mode = RegI THEN
IF x.a1 # 0 THEN
y := x; OCC.GetAReg (x, NIL);
OCC.PutF2 (OCC.LEA, y, x.a0); Unload (y)
END;
x.mode := Reg
ELSIF x.mode IN {LProc, XProc, CallBack} THEN
x.mode := LabI; x.a0 := 0; x.a1 := L; x.label := x.obj.label
END;
IF x.mode = Reg THEN x.a1 := 0; x.a2 := 0; x.obj := NIL END
ELSE
OCS.Mark (127)
END
END Adr;
(*------------------------------------*)
PROCEDURE LoadAdr * (VAR x : OCT.Item);
VAR y : OCT.Item;
BEGIN (* LoadAdr *)
Adr (x);
IF x.mode # Reg THEN
y := x; OCC.GetAReg (x, NIL); OCC.Move (L, y, x)
END;
x.mode := RegI; x.a1 := 0; x.a2 := 0; x.obj := NIL
END LoadAdr;
(*------------------------------------*)
(*
Move the address of a variable, procedure or string constant to the
specified location.
*)
PROCEDURE MoveAdr * (VAR x, y : OCT.Item);
VAR
z : OCT.Item; module : OCT.Object; off, reg : LONGINT;
wordIndex : BOOLEAN;
BEGIN (* MoveAdr *)
IF x.mode IN addressableSet THEN
IF x.mode = Reg THEN
IF x.a0 < A0 THEN OCS.Mark (127)
ELSE OCC.Move (L, x, y)
END
ELSIF (y.mode = Reg) & (y.a0 >= A0) THEN
IF x.typ.form = DynArr THEN Adr (x); OCC.Move (L, x, y)
ELSIF x.mode = Reg THEN OCC.Move (L, x, y)
ELSIF x.mode = Ind THEN
z := x; z.mode := Var; OCC.Move (L, z, y);
IF z.a1 # 0 THEN
z.mode := RegI; z.a0 := y.a0; OCC.PutF2 (OCC.LEA, z, y.a0)
END
ELSIF x.mode = IndX THEN
off := x.a1; reg := x.a2; wordIndex := x.wordIndex;
z := x; z.mode := Var; OCC.Move (L, z, y);
z.mode := RegX; z.a0 := y.a0; z.a1 := off; z.a2 := reg;
z.wordIndex := wordIndex;
OCC.PutF2 (OCC.LEA, z, y.a0)
ELSIF x.mode IN {LProc, XProc, CallBack} THEN
x.mode := Lab; x.a0 := 0; x.a1 := L; x.label := x.obj.label;
OCC.PutF2 (OCC.LEA, x, y.a0)
ELSE
OCC.PutF2 (OCC.LEA, x, y.a0)
END
ELSE
Adr (x); OCC.Move (L, x, y)
END
ELSE
OCS.Mark (127)
END
END MoveAdr;
(*------------------------------------*)
(*
Copies count bytes from src to dst and then terminates dst with a NUL.
*)
PROCEDURE CopyString * ( VAR src, dst, count : OCT.Item );
VAR x : OCT.Item; L0 : INTEGER; i : LONGINT;
BEGIN (* CopyString *)
IF (count.mode = Con) & (count.a0 < 5) THEN (* inline the loop *)
IF count.a0 = 1 THEN
LoadAdr (dst); dst.mode := Pop; (* LEA <dst>,Ad *)
OCC.ForgetReg (dst.a0);
IF src.mode = Con THEN src.a0 := src.a2; src.typ := OCT.chartyp END;
OCC.Move (B, src, dst); (* MOVE.B <src>,(Ad)+ *)
dst.mode := RegI
ELSIF count.a0 > 1 THEN
LoadAdr (src); src.mode := Pop; (* LEA <src>,As *)
LoadAdr (dst); dst.mode := Pop; (* LEA <dst>,Ad *)
OCC.ForgetReg (src.a0); OCC.ForgetReg (dst.a0);
i := count.a0;
WHILE i > 0 DO
OCC.Move (B, src, dst); (* MOVE.B (As)+,(Ad)+ *)
DEC (i)
END;
dst.mode := RegI
ELSE (* src is an empty string *)
IF (dst.typ.form = DynArr) & (dst.mode IN {IndX, RegX}) THEN
LoadAdr (dst) (* LEA <dst>,Ad *)
END
END;
OCC.PutF1 (OCC.CLR, B, dst) (* CLR.B <dst> *)
ELSE
LoadAdr (src); src.mode := Pop; (* LEA <src>,As *)
LoadAdr (dst); dst.mode := Pop; (* LEA <dst>,Ad *)
OCC.ForgetReg (src.a0); OCC.ForgetReg (dst.a0);
IF (count.mode = Con) & (count.a0 < 65536) THEN
count.typ := OCT.inttyp; DEC (count.a0);
Load (count); (* MOVE.W <count>,Dc *)
OCC.Move (B, src, dst); (* 1$ MOVE.B (As)+,(Ad)+ *)
OCC.PutWord (OCC.DBEQ + count.a0);
OCC.PutWord (-4); (* DBEQ.W Dc, 1$ *)
OCC.PutWord (6702H) (* BEQ.S 3$ *)
ELSIF count.mode = Con THEN
DEC (count.a0); Load (count); (* MOVE.L <count>,Dc *)
OCC.Move (B, src, dst); (* 1$ MOVE.B (As)+,(Ad)+ *)
OCC.PutWord (6706H); (* BEQ.S 3$ *)
OCC.PutF7 (OCC.SUBQ, L, 1, count); (* SUBQ.L #1,Dc *)
OCC.PutWord (66F8H) (* BNE 1$ *)
ELSE
Load (count); (* MOVE.L <count>,Dc *)
OCC.PutF7 (OCC.SUBQ, L, 1, count); (* 1$ SUBQ.L #1,Dc *)
OCC.PutWord (6706H); (* BEQ.S 2$ *)
OCC.Move (B, src, dst); (* MOVE.B (As)+,(Ad)+ *)
OCC.PutWord (66F8H); (* BNE.S 1$ *)
OCC.PutWord (6002H) (* BRA.S 3$ *)
END;
dst.mode := RegI;
OCC.PutF1 (OCC.CLR, B, dst) (* 2$ CLR.B <dst> *)
END; (* 3$ *)
END CopyString;
(*------------------------------------*)
(*
Compares src and dst, selecting the correct instruction for the operand
types.
*)
PROCEDURE CMP* ( size : LONGINT; VAR src, dst : OCT.Item );
VAR
BEGIN (* CMP *)
IF (src.mode = Con) THEN
IF (OCM.SmallData & (src.typ.form IN {String, TagTyp}))
OR (dst.mode = Con)
THEN
Load (dst)
END
ELSIF dst.mode # Reg THEN
Load (dst)
END;
IF dst.mode = Reg THEN
OCC.PutF5 (OCC.CMP, size, src, dst)
ELSE
OCC.PutF6 (OCC.CMPI, size, src, dst)
END;
Unload (dst)
END CMP;
END OCI.
(*************************************************************************
$Log: OCI.mod $
Revision 5.17 1995/06/02 18:38:40 fjc
- Various changes to implement the SMALLDATA and RESIDENT
options.
- Added CMP procedure.
Revision 5.16 1995/05/13 23:05:18 fjc
- Converted INTEGER to LONGINT where necessary.
Revision 5.15 1995/05/08 17:05:12 fjc
- Minor corrections.
Revision 5.13 1995/03/25 17:05:01 fjc
- Fixed problems in UnloadDesc().
Revision 5.12 1995/03/23 18:12:30 fjc
- FreeDesc() now calls FreeReg instead of emulating it.
- Cleaned up Adr().
Revision 5.11 1995/03/13 11:30:26 fjc
- Minor fixes to register allocation.
Revision 5.10 1995/03/09 19:09:21 fjc
- Incorporated changes from 5.22.
Revision 5.9 1995/02/27 17:01:02 fjc
- Removed tracing code.
- Changed to use new register handling procedures.
Revision 5.8.1.1 1995/03/08 18:59:09 fjc
- OC 5.22
Revision 5.8 1995/01/26 00:17:17 fjc
- Release 1.5
Revision 5.6 1995/01/03 21:21:29 fjc
- Changed OCG to OCM.
Revision 5.5 1994/12/16 17:20:24 fjc
- Changed Symbol to Label.
Revision 5.4 1994/10/23 16:08:14 fjc
- Fixed register allocation bug in UnloadDesc().
- Changed Multiply() to use OCC.CallKernel().
Revision 5.3 1994/09/25 17:47:18 fjc
- Changed to reflect new object modes and system flags.
Revision 5.2 1994/09/15 10:27:13 fjc
- Replaced switches with pragmas.
Revision 5.1 1994/09/03 19:29:08 fjc
- Bumped version number
*************************************************************************)